/* 
 * File:   Cliente.cpp
 * Author: Maximiliano Monzon (pd 82341)
 * 
 * Created on October 20, 2012, 9:05 AM
 */

#include <cstdio>
#include <iostream>
#include <sstream>
#include "client_Cliente.h"
#include "common_ProtocoloConstantes.h"
#include "common_Excepcion.h"
#include "common_Descriptor.h"

using namespace std;
using namespace TP;
using namespace TP::Comunicacion;

Cliente::Cliente(const string& pIp, const string& pPuerto, std::ostream& pOstream): ostream (pOstream){
    this->ip = pIp;
    this->puerto = pPuerto;
    this->conexion = new Socket (this->ip, this->puerto);
}

Cliente::~Cliente() {
    delete this->conexion;
}

void Cliente::Iniciar() throw (Excepcion&){
    try
    {
        this->conexion->Iniciar();
    }
    catch (Excepcion& pEx)
    {
        pEx.expandirMensaje("No se puede inicar el cliente.");
        throw;
    }
}

void Cliente::Finalizar() throw (Excepcion&){
    try
    {
        this->conexion->Finalizar();
    }
    catch (Excepcion& pEx)
    {
        pEx.expandirMensaje("No se puede finalizar el cliente.");
        throw;
    }
}

void Cliente::getJobPart(Trabajo* pTrabajo) throw (Excepcion&) {
    
    try
    {
        string pComando = "GET­JOB­PART\n";
        this->enviarMensaje(pComando);
        
        string respuesta = "";
        this->esperarRespuesta(respuesta);
        
        Descriptor descriptor (SEPARADOR_CAMPO);
        descriptor.parse(respuesta);
        
        string aux = descriptor.data(0);
        
        if ("JOB-PART" == aux)
        {
            pTrabajo->setTarea (descriptor.data (0));
            pTrabajo->setData(descriptor.data(1));
            pTrabajo->setNumeroProceso (descriptor.data(2));
            pTrabajo->setLongitudClave(descriptor.data(3));
            pTrabajo->setRangoClaves (descriptor.data(4), descriptor.data(5));
        }
        else if ("NO-JOB-PART" == aux)
        {
            string empty = "";
            pTrabajo->setTarea (descriptor.data (0));
            pTrabajo->setData(empty);
            pTrabajo->setNumeroProceso (empty);
            pTrabajo->setLongitudClave(empty);
            pTrabajo->setRangoClaves (empty, empty);
        }
    }
    catch (Excepcion& pEx)
    {
        pEx.expandirMensaje("No se puede ejecutar el comando.");
        throw;
    }
}

void Cliente::setPosibleClave (string &pClave) throw (Excepcion&){
    try
    {
        string pComando = "POSSIBLE-KEY";
        pComando += SEPARADOR_CAMPO;
        pComando += pClave;
        pComando += SEPARADOR_CAMPO;
        pComando += "\n";
        
        this->enviarMensaje(pComando);
        
        string respuesta = "";
        this->esperarRespuesta(respuesta);
        
        Descriptor descriptor (SEPARADOR_CAMPO);
        descriptor.parse(respuesta);
        
        if (OK != descriptor.data(0))
        {
            cerr << endl << descriptor.data(1);
        }
        
    }
    catch (Excepcion& pEx)
    {
        pEx.expandirMensaje("No se puede ejecutar el comando.");
        throw;
    }
}

void Cliente::jobPartFinished (int pNumeroProceso){
    try
    {
        std::stringstream strm;
        strm << pNumeroProceso;
        
        string pComando = "JOB-PART-FINISHED";
        pComando += SEPARADOR_CAMPO;
        pComando += strm.str();
        pComando += SEPARADOR_CAMPO;
        pComando += "\n";
        
        this->enviarMensaje(pComando);
        
        string respuesta = "";
        this->esperarRespuesta(respuesta);
        
        Descriptor descriptor (SEPARADOR_CAMPO);
        descriptor.parse(respuesta);
        
        if (OK != descriptor.data(0))
        {
            cerr << endl << descriptor.data(1);
        }
    }
    catch (Excepcion& pEx)
    {
        pEx.expandirMensaje("No se puede ejecutar el comando.");
        throw;
    }
}

bool Cliente::conectado(){
    try
    {
        string comando = "PING";
        this->enviarMensaje(comando);
        
        string respuesta = "";
        this->esperarRespuesta(respuesta);
        
        return (respuesta.length() > 0);
        
    }
    catch (Excepcion &ex)
    {
        return false;
    }
}

void Cliente::enviarMensaje (const string& pMensaje) throw (Excepcion&){
    
    try
    {
        this->conexion->Escribir(pMensaje);
    }
    catch (Excepcion& pEx)
    {
        pEx.expandirMensaje("Servicio no disponible.");
        throw;
    }
}

void Cliente::esperarRespuesta (string& pMensaje)  throw (Excepcion&) {
    try
    {
        pMensaje = "";
        this->conexion->Leer (pMensaje);
    }
    catch (Excepcion& pEx)
    {
        pEx.expandirMensaje("Fallo al esperar el resultado de la ejecucion.");
        throw;
    }
}

